//! @author Adam Emil Skoog
//! @date   2011-12-24

#ifndef KEDJA_COMPONENT_H_
	#define KEDJA_COMPONENT_H_
	#include <vector>

	namespace kedja
	 {
		class EventManager;
		class EventReceiver;

		/**
		 * A basic component. The core of the entire component system.
		 * Every new component should inherit this class or one of its
		 * children, and be added to another component through the
		 * dedicated member function.
		 * <br /><br />
		 *
		 * Each program may contain only one main component, which can
		 * be obtained from the static function. The first layer of
		 * child components shall be added to that component.
		 * <br /><br />
		 *
		 * All child classes of the component class must have a default
		 * constructor with no arguments.
		 */
		class Component
		 {
			public:
				// Declare functions.
				Component();
				static void createMainComponent();
				static Component *const getMainComponent();
				static void destroyMainComponent();
				static void updateComponentSystem();
				static EventManager *const getEventManager();
				template<class T> T *const createComponent();
				bool destroyComponent(Component *const);
				Component *const previous() const;
				Component *const next() const;
				Component *const parent() const;
				Component *const firstChild() const;
				Component &registerEventReceiver(EventReceiver *const);
				bool deregisterEventReceiver(EventReceiver *const);
				Component &setLayerable(const bool &layerable = true);
				const bool &isLayerable() const;
				const bool &layerableFlagModificationIsPermitted() const;
				~Component();

			protected:
				virtual void render();
				Component &setLayerableFlagModificationPermitted(const bool &permit = true);

			private:
				// Main component.
				static Component    *mainComponent;
				static EventManager *eventManager;

				// Every component is a link of a list.
				Component *previousComponent,
						  *nextComponent,
						  *parentComponent,
						  *firstChildComponent;

				// Event receivers.
				std::vector<EventReceiver *> eventReceivers;

				// Properties.
				bool layerable,
				     layerablePermitted;

				// Declare functions.
				void link(Component *const);
				void unlinkNext();
				Component *const getLastSibling() const;
				void draw();
		 };

		/**
		 * Allocates, adds and returns a component of the specific type as a
		 * child to the component. Do not attempt to delete this pointer.
		 * <br /><br />
		 *
		 * The specified class must be a child of Component, and must have a
		 * default constructor with no arguments.
		 *
		 * @return The new component.
		 */
		template<class T> T *const Component::createComponent()
		 {
			// Allocate the new component.
			T *const result(new T);

			if (!firstChild())
				firstChildComponent = result;
			else
				firstChild()->getLastSibling()->link(result);

			result->parentComponent = this;
			return result;
		 }
	 }
#endif
